// * async function。在函数前面的 async 这个单词表达了一个简单的事情：即这个函数总是返回一个 promise 对象。其它值自动被包装在一个 resolved 的 promise 中。
async function f() {
	return 1
}

f().then((res) => console.log(res)) // 1

// 上面代码与下面这段代码的含义相同：
async function fn() {
	return Promise.resolve(2)
}

fn().then((res) => console.log(res)) // 2

// ***************************************************************************************************************************************************************

// * await promise; 语法 await 后是一个获取了结果的 promise 对象。
async function fn2() {
	let promise = new Promise((resolve, reject) => {
		setTimeout(() => resolve('done'), 1000)
	})

	let result = await promise // 等待，直到 promise resolve 执行

	console.log(result)
}

fn2() // done

// ***************************************************************************************************************************************************************

// * await 接受 “thenables”

class Thenable {
	constructor(num) {
		this.num = num
	}

	then(resolve, reject) {
		// console.log(resolve)
		setTimeout(() => resolve(this.num * 2), 1000)
	}
}

async function fn3() {
	// * 如果 await 接收了一个非 promise 的但是提供了 .then 方法的对象，它就会调用这个 .then 方法，并将内建的函数 resolve 和 reject 作为参数传入。
	let res = await new Thenable(2)
	console.log(res)
}

fn3() // 4

// ***************************************************************************************************************************************************************

// * Class 中的 async 方法

class Waiter {
	async wait() {
		return await Promise.resolve('实例对象原型上的异步方法')
	}
}

new Waiter().wait().then((res) => console.log(res)) // "实例对象原型上的异步方法"

// ***************************************************************************************************************************************************************

// * await Error 处理

// * 如果一个 promise 正常 resolve，那 waait promise 返回的就是其结果。但如果 promise 被 reject，它将 throw 这个错误。
// * 例子：下面两段代码含义相同
async function f2() {
	let res = await Promise.reject(new Error('error'))
	console.log(res)
}

// 上面 await 后的 promise 返回失败，就如同下面这段代码中直接抛出错误的形式去执行的。
async function f3() {
	throw new Error('Whoops')
}

// * 捕获 await 后 promise 错误的三种方式：

// * 1. try catch
async function tryCatch(params) {
	try {
		await new Promise((_, reject) => reject(new Error('error'))) // 如果这里发生错误，代码将不会将不会继续往下执行，而是去执行 catch 中的代码
	} catch (error) {
		console.log(error)
	}
}

// * 2. 函数后 .catch 捕获
async function fnCatch() {
	await new Promise((_, reject) => reject(new Error('error')))
}

fnCatch().catch((err) => console.log('err', err))

// * 3. 使用 unhandledrejection 事件捕获
async function fnUnhandledrejection() {
	await new Promise((_, reject) => reject(new Error('error')))
}

window.addEventListener('unhandledrejection', (err) => {
	console.log('unhandledrejection', err) // unhandledrejection Error: error
})

// ***************************************************************************************************************************************************************

// * 当我们使用 async/await 时，几乎就不会用到 .then 了，因为 await 为我们处理了等待。并且我们使用常规的 try..catch 而不是 .catch。这通常（但不总是）更加方便。

// * async/await 可以和 Promise.all 一起使用：
// 等待结果数组
// let results = await Promise.all([
//   fetch(url1),
//   fetch(url2),
//   ...
// ]);
